home *** CD-ROM | disk | FTP | other *** search
- # Source Generated with Decompyle++
- # File: in.pyo (Python 2.5)
-
- __revision__ = '$Id: streamtls.py 667 2006-12-11 16:48:59Z jajcus $'
- __docformat__ = 'restructuredtext en'
- import socket
- import sys
- import errno
- import logging
- from pyxmpp.streambase import StreamBase, STREAM_NS
- from pyxmpp.streambase import FatalStreamError, StreamEncryptionRequired
- from pyxmpp.exceptions import TLSNegotiationFailed, TLSError, TLSNegotiatedButNotAvailableError
-
- try:
- import M2Crypto
- if M2Crypto.version_info < (0, 16):
- tls_available = 0
- else:
- from M2Crypto import SSL
- from M2Crypto.SSL import SSLError
- import M2Crypto.SSL.cb as M2Crypto
- tls_available = 1
- except ImportError:
- tls_available = 0
-
- if not tls_available:
-
- class SSLError(Exception):
- pass
-
-
- TLS_NS = 'urn:ietf:params:xml:ns:xmpp-tls'
-
- class TLSSettings:
-
- def __init__(self, require = False, verify_peer = True, cert_file = None, key_file = None, cacert_file = None, verify_callback = None, ctx = None):
- self.require = require
- self.ctx = ctx
- self.verify_peer = verify_peer
- self.cert_file = cert_file
- self.cacert_file = cacert_file
- self.key_file = key_file
- self.verify_callback = verify_callback
-
-
-
- class StreamTLSMixIn:
- tls_available = tls_available
-
- def __init__(self, tls_settings = None):
- self.tls_settings = tls_settings
- self._StreamTLSMixIn__logger = logging.getLogger('pyxmpp.StreamTLSMixIn')
-
-
- def _reset_tls(self):
- self.tls = None
- self.tls_requested = False
-
-
- def _make_stream_tls_features(self, features):
- if self.tls_settings and not (self.tls):
- tls = features.newChild(None, 'starttls', None)
- ns = tls.newNs(TLS_NS, None)
- tls.setNs(ns)
- if self.tls_settings.require:
- tls.newChild(None, 'required', None)
-
-
- return features
-
-
- def _write_raw(self, data):
- logging.getLogger('pyxmpp.Stream.out').debug('OUT: %r', data)
-
- try:
- if self.tls:
- self.tls.setblocking(True)
-
- self.socket.send(data)
- if self.tls:
- self.tls.setblocking(False)
- except (IOError, OSError, socket.error):
- e = None
- raise FatalStreamError('IO Error: ' + str(e))
- except SSLError:
- e = None
- raise TLSError('TLS Error: ' + str(e))
-
-
-
- def _read_tls(self):
- if self.eof:
- return None
-
- while self.socket:
-
- try:
- r = self.socket.read()
- if r is None:
- return None
- except socket.error:
- e = None
- if e.args[0] != errno.EINTR:
- raise
-
- return None
-
- self._feed_reader(r)
-
-
- def _read(self):
- self._StreamTLSMixIn__logger.debug('StreamTLSMixIn._read(), socket: %r', self.socket)
- if self.tls:
- self._read_tls()
- else:
- StreamBase._read(self)
-
-
- def _process(self):
-
- try:
- StreamBase._process(self)
- except SSLError:
- e = None
- self.close()
- raise TLSError('TLS Error: ' + str(e))
-
-
-
- def _process_node_tls(self, xmlnode):
- ns_uri = xmlnode.ns().getContent()
- if ns_uri == STREAM_NS:
- return False
- elif ns_uri == TLS_NS:
- self._process_tls_node(xmlnode)
- return True
-
- if self.tls_settings and self.tls_settings.require and not (self.tls):
- raise StreamEncryptionRequired, 'TLS encryption required and not started yet'
-
- return False
-
-
- def _handle_tls_features(self):
- ctxt = self.doc_in.xpathNewContext()
- ctxt.setContextNode(self.features)
- ctxt.xpathRegisterNs('tls', TLS_NS)
-
- try:
- tls_n = ctxt.xpathEval('tls:starttls')
- tls_required_n = ctxt.xpathEval('tls:starttls/tls:required')
- finally:
- ctxt.xpathFreeContext()
-
- if not self.tls:
- if tls_required_n and not (self.tls_settings):
- raise FatalStreamError, 'StartTLS support disabled, but required by peer'
-
- if self.tls_settings and self.tls_settings.require and not tls_n:
- raise FatalStreamError, 'StartTLS required, but not supported by peer'
-
- if self.tls_settings and tls_n:
- self._StreamTLSMixIn__logger.debug('StartTLS negotiated')
- if not self.tls_available:
- raise TLSNegotiatedButNotAvailableError, 'StartTLS negotiated, but not available (M2Crypto >= 0.16 module required)'
-
- if self.initiator:
- self._request_tls()
-
- else:
- self._StreamTLSMixIn__logger.debug('StartTLS not negotiated')
-
-
-
- def _request_tls(self):
- self.tls_requested = 1
- self.features = None
- root = self.doc_out.getRootElement()
- xmlnode = root.newChild(None, 'starttls', None)
- ns = xmlnode.newNs(TLS_NS, None)
- xmlnode.setNs(ns)
- self._write_raw(xmlnode.serialize(encoding = 'UTF-8'))
- xmlnode.unlinkNode()
- xmlnode.freeNode()
-
-
- def _process_tls_node(self, xmlnode):
- if not (self.tls_settings) or not tls_available:
- self._StreamTLSMixIn__logger.debug('Unexpected TLS node: %r' % xmlnode.serialize())
- return False
-
- if self.initiator:
- if xmlnode.name == 'failure':
- raise TLSNegotiationFailed, 'Peer failed to initialize TLS connection'
- elif xmlnode.name != 'proceed' or not (self.tls_requested):
- self._StreamTLSMixIn__logger.debug('Unexpected TLS node: %r' % xmlnode.serialize())
- return False
-
-
- try:
- self.tls_requested = 0
- self._make_tls_connection()
- self.socket = self.tls
- except SSLError:
- e = None
- self.tls = 0
- raise TLSError('TLS Error: ' + str(e))
-
- self._StreamTLSMixIn__logger.debug('Restarting XMPP stream')
- self._restart_stream()
- return True
- else:
- raise FatalStreamError, 'TLS not implemented for the receiving side yet'
-
-
- def _make_tls_connection(self):
- if not tls_available or not (self.tls_settings):
- raise TLSError, 'TLS is not available'
-
- self.state_change('tls connecting', self.peer)
- self._StreamTLSMixIn__logger.debug('Creating TLS context')
- if self.tls_settings.ctx:
- ctx = self.tls_settings.ctx
- else:
- ctx = SSL.Context('tlsv1')
- verify_callback = self.tls_settings.verify_callback
- if not verify_callback:
- verify_callback = self.tls_default_verify_callback
-
- if self.tls_settings.verify_peer:
- self._StreamTLSMixIn__logger.debug('verify_peer, verify_callback: %r', verify_callback)
- ctx.set_verify(SSL.verify_peer, 10, verify_callback)
- else:
- ctx.set_verify(SSL.verify_none, 10)
- if self.tls_settings.cert_file:
- ctx.use_certificate_chain_file(self.tls_settings.cert_file)
- if self.tls_settings.key_file:
- ctx.use_PrivateKey_file(self.tls_settings.key_file)
- else:
- ctx.use_PrivateKey_file(self.tls_settings.cert_file)
- ctx.check_private_key()
-
- if self.tls_settings.cacert_file:
-
- try:
- ctx.load_verify_location(self.tls_settings.cacert_file)
- except AttributeError:
- ctx.load_verify_locations(self.tls_settings.cacert_file)
- except:
- None<EXCEPTION MATCH>AttributeError
-
-
- None<EXCEPTION MATCH>AttributeError
- self._StreamTLSMixIn__logger.debug('Creating TLS connection')
- self.tls = SSL.Connection(ctx, self.socket)
- self._StreamTLSMixIn__logger.debug('Setting up TLS connection')
- self.tls.setup_ssl()
- self._StreamTLSMixIn__logger.debug('Setting TLS connect state')
- self.tls.set_connect_state()
- self._StreamTLSMixIn__logger.debug('Starting TLS handshake')
- self.tls.connect_ssl()
- self.state_change('tls connected', self.peer)
- self.tls.setblocking(0)
-
- try:
- raise Exception
- except:
- pass
-
-
-
- def tls_is_certificate_valid(self, store_context):
- depth = store_context.get_error_depth()
- if depth > 0:
- return True
-
- cert = store_context.get_current_cert()
- cn = cert.get_subject().CN
- if str(cn) != self.peer.as_utf8():
- return False
-
- return True
-
-
- def tls_default_verify_callback(self, ok, store_context):
-
- try:
- self._StreamTLSMixIn__logger.debug('tls_default_verify_callback(ok=%i, store=%r)' % (ok, store_context))
- X509 = X509
- m2 = m2
- import M2Crypto
- depth = store_context.get_error_depth()
- cert = store_context.get_current_cert()
- cn = cert.get_subject().CN
- self._StreamTLSMixIn__logger.debug(' depth: %i cert CN: %r' % (depth, cn))
- if ok and not tls_is_certificate_valid(store_context):
- self._StreamTLSMixIn__logger.debug(u'Common name does not match peer name (%s != %s)' % (cn, self.peer.as_utf8))
- return False
-
- return ok
- except:
- self._StreamTLSMixIn__logger.exception('Exception caught')
- raise
-
-
-
- def get_tls_connection(self):
- return self.tls
-
-
-